package apuntes;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import aima.core.agent.Action;
import aima.core.agent.impl.DynamicAction;

import aima.core.search.framework.ActionsFunction;
import aima.core.search.framework.Problem;
import aima.core.search.framework.ResultFunction;
import aima.core.search.framework.Search;
import aima.core.search.framework.SearchAgent;
import aima.core.search.uninformed.DepthLimitedSearch;
import aima.core.search.uninformed.IterativeDeepeningSearch;

public class EstadoMisioneros {

	private int numMisioneros; // numMisioneros en orilla izquierda
	private int numCanibales; // numCAnibales en orilla izquierda
	private boolean barcaIzq; // true si barca en orilla izquierda
	
	public static Action M = new DynamicAction("M");
	public static Action MM = new DynamicAction("MM");
	public static Action C = new DynamicAction("C");
	public static Action CC = new DynamicAction("CC");
	public static Action MC = new DynamicAction("MC");
	
		
		public EstadoMisioneros() {
			this(3, 3, true);
			}
		
			public EstadoMisioneros(EstadoMisioneros mc) {
			this(mc.getnMisioneros(), mc.getnCanibales(), mc.isBarcaIzq());
			}
			public EstadoMisioneros(int nMisioneros, int nCanibales, boolean
			barcaIzq) {
			this.numMisioneros = nMisioneros;
			this.numCanibales = nCanibales;
			this.barcaIzq = barcaIzq;
	}
			
	public int getnMisioneros(){
		return numMisioneros;
	}
	
	public int getnCanibales(){
		return numCanibales;
	}
	
	public boolean isBarcaIzq(){
		return barcaIzq;
	}
	/********************************************************/

	public void moveM() {
		if (barcaIzq)
		numMisioneros--;
		else
		numMisioneros++;
		cambiarDeOrilla();
		}
	
	public void moveMM() {
		if (barcaIzq)
		numMisioneros = numMisioneros - 2;
		else
		numMisioneros = numMisioneros + 2;
		cambiarDeOrilla();
		}
	
	public void moveC() {
		if (barcaIzq)
		numCanibales--;
		else
		numCanibales++;
		cambiarDeOrilla();
		}
	
	public void moveCC() {
		if (barcaIzq)
		numCanibales = numCanibales - 2;
		else
		numCanibales = numCanibales + 2;
		cambiarDeOrilla();
		}
	
	public void moveMC() {
		if (barcaIzq){
			numCanibales++;
			numMisioneros++;
		}
		else{
			numCanibales--;
			numMisioneros--;
		}
		cambiarDeOrilla();
		}
	
	public void cambiarDeOrilla(){
		barcaIzq = !barcaIzq;
	}
	
	public boolean movimientoValido(Action where) {
		boolean valido = false;
		if (where.equals(M)) {
			if ((barcaIzq && numMisioneros > 0) || (!barcaIzq && numMisioneros < 3)) {
				EstadoMisioneros estadoSiguiente = new EstadoMisioneros(this);
				estadoSiguiente.moveM();
				valido = !estadoSiguiente.peligro();
			}
			else valido = false;
			if (valido) System.out.println("M OK");
		}
		else if (where.equals(MM)) {
			if ((barcaIzq && numMisioneros > 1) || (!barcaIzq && numMisioneros < 2)) {
				EstadoMisioneros estadoSiguiente = new EstadoMisioneros(this);
				estadoSiguiente.moveMM();
				valido = !estadoSiguiente.peligro();
			}
			else valido = false;
			if (valido) System.out.println("MM OK");
		}
		else if (where.equals(C)) {
			if ((barcaIzq && numCanibales > 0) || (!barcaIzq && numCanibales < 3)) {
				EstadoMisioneros estadoSiguiente = new EstadoMisioneros(this);
				estadoSiguiente.moveC();
				valido = !estadoSiguiente.peligro();
			}
			else valido = false;
			if (valido) System.out.println("C OK");
		}
		else if (where.equals(CC)) {
			if ((barcaIzq && numCanibales > 1) || (!barcaIzq && numCanibales < 2)) {
				EstadoMisioneros estadoSiguiente = new EstadoMisioneros(this);
				estadoSiguiente.moveCC();
				valido = !estadoSiguiente.peligro();
			}
			else valido = false;
			if (valido) System.out.println("CC OK");
		}
		else if (where.equals(MC)) {
			if ((barcaIzq && numCanibales > 0 && numMisioneros > 0) || (!barcaIzq && numCanibales < 2 && numMisioneros < 2)) {
				EstadoMisioneros estadoSiguiente = new EstadoMisioneros(this);
				estadoSiguiente.moveMC();
				valido = !estadoSiguiente.peligro();
			}
			else valido = false;
			if (valido) System.out.println("MC OK");
		}
		
		return valido;
	}
	
	private boolean peligro() {
		if (((numMisioneros < numCanibales) && (numMisioneros != 0))
		|| ((numMisioneros > numCanibales) && (numMisioneros != 3)))
		return true;
		else
		return false;
		}
	
	public boolean equals(Object o) {
		if (this == o) {
		return true;
		}
		if ((o == null) || (this.getClass() != o.getClass())) {
		return false;
		}
		EstadoMisioneros otroEstado = (EstadoMisioneros) o;
		if ((this.numMisioneros == otroEstado.getnMisioneros()) &&
		(this.numCanibales == otroEstado.getnCanibales()) &&
		(this.barcaIzq == otroEstado.isBarcaIzq()))
		return true;
		else
		return false;
		}
		public int hashCode() {
		return (100 * numMisioneros) + (10 * numCanibales) + (barcaIzq ? 1 : 0);
		}

		private static void eightPuzzleDLSDemo(EstadoMisioneros estado) {
			System.out.println("\nMisioneros recursive DLS (9) -->");
			try {
				Problem problem = new Problem(estado, MisionerosFunctionFactory
						.getActionsFunction(), MisionerosFunctionFactory
						.getResultFunction(), new MisionerosGoalTest());
				Search search = new DepthLimitedSearch(9);
				SearchAgent agent = new SearchAgent(problem, search);
				printActions(agent.getActions());
				printInstrumentation(agent.getInstrumentation());
			} catch (Exception e) {
				e.printStackTrace();
			}

		}

		private static void eightPuzzleIDLSDemo(EstadoMisioneros estado) {
			System.out.println("\nEightPuzzleDemo Iterative DLS -->");
			try {
				Problem problem = new Problem(estado, MisionerosFunctionFactory
						.getActionsFunction(), MisionerosFunctionFactory
						.getResultFunction(), new MisionerosGoalTest());
				Search search = new IterativeDeepeningSearch();
				SearchAgent agent = new SearchAgent(problem, search);
				printActions(agent.getActions());
				printInstrumentation(agent.getInstrumentation());
			} catch (Exception e) {
				e.printStackTrace();
			}

		}
		
		private static void printInstrumentation(Properties properties) {
			Iterator<Object> keys = properties.keySet().iterator();
			while (keys.hasNext()) {
				String key = (String) keys.next();
				String property = properties.getProperty(key);
				System.out.println(key + " : " + property);
			}

		}

		private static void printActions(List<Action> actions) {
			for (int i = 0; i < actions.size(); i++) {
				String action = actions.get(i).toString();
				System.out.println(action);
			}
		}
		
		public static void main(String[] args){
			EstadoMisioneros estado = new EstadoMisioneros();
			eightPuzzleDLSDemo(estado);
			
			eightPuzzleIDLSDemo(estado);
		}
}
